package com.powernode.ssm.utils;


import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Java 8 日期时间工具类（基于 LocalDate / LocalDateTime / YearMonth）
 * 提供常用的日期时间操作：当前时间、格式化、偏移、月初月末、季度、年月、周末节假日、时间差等
 * 所有方法均有详细注释，每个新增方法均附带【使用示例代码块注释】
 */
public class DateTimeUtils {

    // 默认日期时间格式：yyyy-MM-dd HH:mm:ss
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    // 示例：固定的节假日日期集合（仅用于演示，实际应该从数据库/配置文件中加载，并考虑调休逻辑）
    private static final Set<String> FIXED_HOLIDAYS = new HashSet<>(Arrays.asList(
            "2024-01-01", // 元旦
            "2024-05-01", // 劳动节
            "2024-10-01", // 国庆节
            "2024-10-02",
            "2024-10-03"
    ));

    // 私有构造方法，防止工具类被实例化
    private DateTimeUtils() {
    }

    // ========== 基础功能：当前时间、格式化、解析、偏移 ==========

    /**
     * 获取当前服务器时间（LocalDateTime）
     *
     * @return 当前系统时间的 LocalDateTime 对象
     */
    public static LocalDateTime now() {
        return LocalDateTime.now();
    }

    /**
     * 获取当前时间的格式化字符串（默认格式：yyyy-MM-dd HH:mm:ss）
     *
     * @return 格式化后的当前时间字符串
     */
    public static String nowString() {
        return format(now());
    }

    /**
     * 获取当前日期的格式化字符串（默认格式：yyyy-MM-dd）
     *
     * @return 格式化后的当前时间字符串
     */

    public static String dateString() {
        return format(now()).substring(0,10);
    }

    /**
     * 格式化 LocalDateTime 为字符串（使用默认格式）
     *
     * @param dateTime 要格式化的日期时间对象
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime) {
        return format(dateTime, DEFAULT_DATE_TIME_FORMAT);
    }

    /**
     * 格式化 LocalDateTime 为字符串（自定义格式）
     *
     * @param dateTime 要格式化的日期时间
     * @param pattern  格式模板，如 yyyy-MM-dd HH:mm:ss
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 解析字符串为 LocalDateTime（默认格式）
     *
     * @param dateTimeStr 日期时间字符串
     * @return 解析后的 LocalDateTime 对象
     */
    public static LocalDateTime parse(String dateTimeStr) {
        return parse(dateTimeStr, DEFAULT_DATE_TIME_FORMAT);
    }

    /**
     * 解析字符串为 LocalDateTime（自定义格式）
     *
     * @param dateTimeStr 日期时间字符串
     * @param pattern     格式，如 yyyy-MM-dd HH:mm:ss
     * @return 解析后的 LocalDateTime 对象
     */
    public static LocalDateTime parse(String dateTimeStr, String pattern) {
        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
            return null;
        }
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取当前时间偏移 n 天后的日期时间
     *
     * @param days 偏移天数，正数表示未来，负数表示过去
     * @return 偏移后的 LocalDateTime
     */
    public static LocalDateTime plusDays(long days) {
        return now().plusDays(days);
    }

    /**
     * 获取当前时间偏移 n 天后的格式化字符串
     *
     * @param days 偏移天数
     * @return 格式化后的日期时间字符串
     */
    public static String plusDaysString(long days) {
        return format(plusDays(days));
    }

    // ========== 月初 / 月末 ==========

    /**
     * 获取当前月份的第一天（LocalDate）
     */
    public static LocalDate getFirstDayOfCurrentMonth() {
        return LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取当前月份第一天的开始时间（00:00:00）
     */
    public static LocalDateTime getFirstDayOfMonthStart() {
        return getFirstDayOfCurrentMonth().atStartOfDay();
    }

    /**
     * 获取当前月份第一天的结束时间（23:59:59）
     */
    public static LocalDateTime getFirstDayOfMonthEnd() {
        return getFirstDayOfCurrentMonth().atTime(23, 59, 59);
    }

    /**
     * 获取当前月份的最后一天（LocalDate）
     */
    public static LocalDate getLastDayOfCurrentMonth() {
        return LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取当前月份最后一天的开始时间（00:00:00）
     */
    public static LocalDateTime getLastDayOfMonthStart() {
        return getLastDayOfCurrentMonth().atStartOfDay();
    }

    /**
     * 获取当前月份最后一天的结束时间（23:59:59）
     */
    public static LocalDateTime getLastDayOfMonthEnd() {
        return getLastDayOfCurrentMonth().atTime(23, 59, 59);
    }

    /**
     * 获取指定日期所在月份的第一天
     */
    public static LocalDate getFirstDayOfMonth(LocalDate date) {
        if (date == null) return null;
        return date.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取指定日期所在月份的最后一天
     */
    public static LocalDate getLastDayOfMonth(LocalDate date) {
        if (date == null) return null;
        return date.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取某年某月的第一天
     */
    public static LocalDate getFirstDayOfMonth(int year, int month) {
        return LocalDate.of(year, month, 1);
    }

    /**
     * 获取某年某月的最后一天
     */
    public static LocalDate getLastDayOfMonth(int year, int month) {
        return LocalDate.of(year, month, 1).with(TemporalAdjusters.lastDayOfMonth());
    }

    // ========== 季度相关 ==========

    /**
     * 获取当前季度（1 ~ 4）
     */
    public static int getCurrentQuarter() {
        return (LocalDate.now().getMonthValue() - 1) / 3 + 1;
    }

    /**
     * 获取指定日期所在的季度（1 ~ 4）
     */
    public static int getQuarter(LocalDate date) {
        if (date == null) return 0;
        return (date.getMonthValue() - 1) / 3 + 1;
    }

    /**
     * 获取当前季度的第一天
     */
    public static LocalDate getFirstDayOfCurrentQuarter() {
        return getFirstDayOfQuarter(LocalDate.now());
    }

    /**
     * 获取当前季度的最后一天
     */
    public static LocalDate getLastDayOfCurrentQuarter() {
        return getLastDayOfQuarter(LocalDate.now());
    }

    /**
     * 获取某年某季度的第一天
     */
    public static LocalDate getFirstDayOfQuarter(int year, int quarter) {
        int month = (quarter - 1) * 3 + 1;
        return LocalDate.of(year, month, 1);
    }

    /**
     * 获取某年某季度的最后一天
     */
    public static LocalDate getLastDayOfQuarter(int year, int quarter) {
        int month = quarter * 3;
        return LocalDate.of(year, month, 1).with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取指定日期所在季度的第一天
     */
    public static LocalDate getFirstDayOfQuarter(LocalDate date) {
        if (date == null) return null;
        int quarter = getQuarter(date);
        int year = date.getYear();
        int month = (quarter - 1) * 3 + 1;
        return LocalDate.of(year, month, 1);
    }

    /**
     * 获取指定日期所在季度的最后一天
     */
    public static LocalDate getLastDayOfQuarter(LocalDate date) {
        if (date == null) return null;
        int quarter = getQuarter(date);
        int year = date.getYear();
        int month = quarter * 3;
        return LocalDate.of(year, month, 1).with(TemporalAdjusters.lastDayOfMonth());
    }

    // ========== 年月信息 ==========

    /**
     * 获取当前年份
     */
    public static int getCurrentYear() {
        return LocalDate.now().getYear();
    }

    /**
     * 获取当前月份（1 ~ 12）
     */
    public static int getCurrentMonth() {
        return LocalDate.now().getMonthValue();
    }

    /**
     * 获取指定日期的年份
     */
    public static int getYear(LocalDate date) {
        return date != null ? date.getYear() : 0;
    }

    /**
     * 获取指定日期的月份（1 ~ 12）
     */
    public static int getMonth(LocalDate date) {
        return date != null ? date.getMonthValue() : 0;
    }

    /**
     * 获取某年某月的总天数
     */
    public static int getDaysInMonth(int year, int month) {
        return LocalDate.of(year, month, 1).lengthOfMonth();
    }

    // ========== 周末 / 节假日判断 ==========

    /**
     * 判断是否是周末（周六或周日）
     */
    public static boolean isWeekend(LocalDate date) {
        if (date == null) return false;
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
    }

    /**
     * 判断是否是周末（基于 LocalDateTime）
     */
    public static boolean isWeekend(LocalDateTime dateTime) {
        if (dateTime == null) return false;
        return isWeekend(dateTime.toLocalDate());
    }

    /**
     * 判断是否是节假日（简化版，仅示例，固定日期）
     */
    public static boolean isHoliday(LocalDate date) {
        if (date == null) return false;
        return FIXED_HOLIDAYS.contains(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
    }

    /**
     * 判断是否是工作日（非周末且非节假日）
     */
    public static boolean isWorkday(LocalDate date) {
        return !isWeekend(date) && !isHoliday(date);
    }

    // ========== 时间差 ==========

    /**
     * 计算两个 LocalDateTime 之间的天数差
     */
    public static long daysBetween(LocalDateTime start, LocalDateTime end) {
        if (start == null || end == null) return 0L;
        return Duration.between(start, end).toDays();
    }

    /**
     * 计算两个 LocalDate 之间的天数差
     */
    public static long daysBetween(LocalDate start, LocalDate end) {
        if (start == null || end == null) return 0L;
        return ChronoUnit.DAYS.between(start, end);
    }

    // ========== ✅ 新增实用方法：传参日期的相关计算 ==========

    /**
     * 获取传参日期的上一个月的同一天
     * 如果上个月没有相同的日期（例如 3月31日 -> 2月没有31日），则返回上个月的最后一天
     *
     * 【使用示例】
     * LocalDate date = LocalDate.of(2024, 3, 31);
     * LocalDate result = DateTimeUtils.getSameDayOfPreviousMonth(date);
     * System.out.println("2024-03-31 的上一个月同一天: " + result); // 2024-02-29
     */
    public static LocalDate getSameDayOfPreviousMonth(LocalDate date) {
        if (date == null) return null;
        LocalDate previousMonth = date.minusMonths(1);
        int dayOfMonth = date.getDayOfMonth();
        return previousMonth.withDayOfMonth(Math.min(dayOfMonth, previousMonth.lengthOfMonth()));
    }

    /**
     * 获取传参日期的上一个年的同一天
     * 如果上一年没有相同的日期（例如 2020-02-29 -> 2019-02-29 不存在），则返回上一年的最后一天
     *
     * 【使用示例】
     * LocalDate date = LocalDate.of(2020, 2, 29);
     * LocalDate result = DateTimeUtils.getSameDayOfPreviousYear(date);
     * System.out.println("2020-02-29 的上一年同一天: " + result); // 2019-02-28
     */
    public static LocalDate getSameDayOfPreviousYear(LocalDate date) {
        if (date == null) return null;
        LocalDate previousYear = date.minusYears(1);
        int dayOfMonth = date.getDayOfMonth();
        return previousYear.withDayOfMonth(Math.min(dayOfMonth, previousYear.lengthOfMonth()));
    }

    /**
     * 获取传参月份（年 + 月）的上一个月
     * 返回类型为 YearMonth，例如：2024-01 -> 2023-12
     *
     * 【使用示例】
     * YearMonth prev = DateTimeUtils.getPreviousMonth(2024, 1);
     * System.out.println("2024-01 的上一个月: " + prev); // 2023-12
     */
    public static YearMonth getPreviousMonth(int year, int month) {
        if (month == 1) {
            return YearMonth.of(year - 1, 12);
        } else {
            return YearMonth.of(year, month - 1);
        }
    }

    /**
     * 获取传参月份（年 + 月）的上一年同一月
     * 例如：2024-03 -> 2023-03
     *
     * 【使用示例】
     * YearMonth sameMonthLastYear = DateTimeUtils.getSameMonthOfPreviousYear(2024, 3);
     * System.out.println("2024-03 的上一年同一月: " + sameMonthLastYear); // 2023-03
     */
    public static YearMonth getSameMonthOfPreviousYear(int year, int month) {
        return YearMonth.of(year - 1, month);
    }

    public static void main(String[] args) {
        System.out.println("========== DateTimeUtils 全部方法测试 ==========");

        // ---------- 基础：当前时间 -----------
        System.out.println("\n--- 当前时间相关 ---");
        System.out.println("当前时间: " + nowString());
        System.out.println("当前日期: " + dateString());
        System.out.println("当前时间 + 3天: " + plusDaysString(3));

        // ---------- 月初 / 月末 ----------
        System.out.println("\n--- 月初 / 月末 ---");
        System.out.println("当前月份第一天: " + getFirstDayOfCurrentMonth());
        System.out.println("当前月份最后一天: " + getLastDayOfCurrentMonth());
        System.out.println("当前月份第一天 00:00:00: " + getFirstDayOfMonthStart());
        System.out.println("当前月份最后一天 23:59:59: " + getLastDayOfMonthEnd());

        // 指定日期：2024-03-31
        LocalDate testDate31 = LocalDate.of(2024, 3, 31);
        System.out.println("指定日期 2024-03-31 的当月最后一天: " + getLastDayOfMonth(testDate31));

        // ---------- 季度相关 ----------
        System.out.println("\n--- 季度相关 ---");
        System.out.println("当前季度: " + getCurrentQuarter());
        LocalDate sampleDate = LocalDate.of(2024, 5, 15); // Q2
        System.out.println("指定日期 " + sampleDate + " 所在季度: " + getQuarter(sampleDate));
        System.out.println("该季度第一天: " + getFirstDayOfQuarter(sampleDate));
        System.out.println("该季度最后一天: " + getLastDayOfQuarter(sampleDate));

        // ---------- 年月信息 ----------
        System.out.println("\n--- 年月信息 ---");
        System.out.println("当前年份: " + getCurrentYear());
        System.out.println("当前月份: " + getCurrentMonth());
        System.out.println("2024年2月有几天: " + getDaysInMonth(2024, 2)); // 闰年
        System.out.println("2023年2月有几天: " + getDaysInMonth(2023, 2)); // 非闰年

        // ---------- 周末 / 节假日 ----------
        System.out.println("\n--- 周末 / 节假日判断 ---");
        LocalDate weekendTest = LocalDate.of(2024, 6, 1); // 星期六
        System.out.println(weekendTest + " 是周末吗？ " + isWeekend(weekendTest));
        System.out.println(weekendTest + " 是工作日吗？ " + isWorkday(weekendTest));

        LocalDate holidayTest = LocalDate.of(2024, 10, 1); // 国庆节
        System.out.println(holidayTest + " 是节假日吗？ " + isHoliday(holidayTest));
        System.out.println(holidayTest + " 是工作日吗？ " + isWorkday(holidayTest));

        // ---------- 新增方法：上一个月的同一天等 ----------
        System.out.println("\n--- 新增实用方法 ---");

        // 1. 上一个月的同一天
        LocalDate date1 = LocalDate.of(2024, 3, 31);
        LocalDate sameDayLastMonth = getSameDayOfPreviousMonth(date1);
        System.out.println("2024-03-31 的上一个月同一天: " + sameDayLastMonth); // 应为 2024-02-29

        // 2. 上一年的同一天
        LocalDate date2 = LocalDate.of(2020, 2, 29); // 闰日
        LocalDate sameDayLastYear = getSameDayOfPreviousYear(date2);
        System.out.println("2020-02-29 的上一年同一天: " + sameDayLastYear); // 应为 2019-02-28

        // 3. 传参月份的上一个月（YearMonth）
        YearMonth prevMonth = getPreviousMonth(2024, 1); // 2024-01 => 2023-12
        System.out.println("2024-01 的上一个月: " + prevMonth);

        // 4. 传参月份的上一年同一月
        YearMonth sameMonthLastYear = getSameMonthOfPreviousYear(2024, 3); // 2024-03 => 2023-03
        System.out.println("2024-03 的上一年同一月: " + sameMonthLastYear);
    }
}